/*
 * Copyright 2009 Johnson Consulting Services
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.johnsoncs.gwt.widgets.server.export;

import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportException;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRequest;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRuntimeException;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportStatus;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportStatus.Status;

/**
 * Initiates an asynchronous export
 * @author wilj
 *
 */
@SuppressWarnings("unchecked")
public class ExportManager {
	private static class ExportWorker implements Runnable {
		private final String exportId;
		private final ExportRequest request;
		private final ExportFormat format;
		private final ExportModel model;
		private final ExportStorage storage;
		private final ExportStatusProxy proxy;

		public ExportWorker(final String exportId, final ExportRequest request, final ExportFormat format,
				final ExportModel model, final ExportStorage storage, final ExportStatusProxy proxy) {
			this.exportId = exportId;
			this.request = request;
			this.format = format;
			this.model = model;
			this.storage = storage;
			this.proxy = proxy;
		}

		@Override
		public void run() {
			try {
				final String fileName = format.export(exportId, request, model, storage);
				proxy
						.setExportStatus(new ExportStatus(exportId, Status.COMPLETE, fileName, format.getMimeType(),
						format.isAttachment(),
						null));
			} catch (final Throwable t) {
				// TODO re-enable SLF4J after switch over to GWT 2.0 due to issue #3496
				//logger.error("Error processing export request", t);
				logger.log(Level.SEVERE, "Error processing export request", t);
				proxy.setExportStatus(new ExportStatus(exportId, Status.FAILED, null, null, false, t));
				throw new ExportRuntimeException("Unhandled error during export", t);
			}
		}

	}

	// TODO re-enable SLF4J after switch over to GWT 2.0 due to issue #3496
	//private static final Logger logger = LoggerFactory.getLogger(ExportManager.class);
	private static final Logger logger = Logger.getLogger(ExportManager.class.getName());

	/**
	 * Initiates an asynchronous export, and blocks for up to 10 seconds before returning.
	 * @param request the configuration for the export request
	 * @param format the ExportFormat to use for the export
	 * @param model the model from which to export rows
	 * @param storage the ExportStorage to which the export results will be written
	 * @return ExportStatus for the export request
	 * @throws ExportException
	 */
	public static ExportStatus export(final ExportRequest request, final ExportFormat format,
			final ExportModel model, final ExportStorage storage,
			final ExportStatusProxy proxy) throws ExportException {
		final String exportId = UUID.randomUUID().toString();

		ExportStatus result = new ExportStatus(exportId, Status.PENDING, null, null, false, null);
		proxy.setExportStatus(result);

		final Thread worker = new Thread(new ExportWorker(exportId, request, format, model, storage, proxy));
		worker.setDaemon(true);
		worker.start();

		// wait up to 10 seconds for export to finish, to improve response time for smaller exports
		for (int i = 0; i < 10; i++) {
			try {
				Thread.sleep(1000);
			} catch (final InterruptedException ie) {
				Thread.currentThread().interrupt();
			}
			result = proxy.getExportStatus(exportId);
			if (result.getStatus() != Status.PENDING) {
				break;
			}
		}

		return result;
	}

	private ExportManager() {
	}
}
